﻿using System;
using System.Collections.Generic;
using System.Linq;
using Hammock;

namespace OpenNOSClient
{
    public abstract class OpenNOSRestClientAsync : OpenNOSRestClientBase
    {
        /// <summary>
        /// Callback method
        /// </summary>
        /// <typeparam name="T">The type</typeparam>
        /// <param name="response">The response.</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
        public delegate void OpenNOSRestCallback<T>(T response);

        /// <summary>
        /// Initializes a new instance of the <see cref="OpenNOSRestClient"/> class.
        /// </summary>
        /// <param name="key">The key.</param>
        protected OpenNOSRestClientAsync(string key)
            : base(key)
        {
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public void GetLatestArticlesAsync(OpenNOSRestCallback<IEnumerable<Article>> openNOSCallback, OpenNOSCategory category)
        {
            string path = GeneratePath(OpenNOSRequestTypes.LatestArticles, category);

            var callback =
                new RestCallback<OpenNOSResponse>((restRequest, restResponse, userState) =>
                {
                    openNOSCallback.Invoke(restResponse.ContentEntity.LatestArticles.FirstOrDefault());
                });

            BeginRequest<OpenNOSResponse>(callback, path);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public void GetLatestAudioAsync(OpenNOSRestCallback<IEnumerable<Audio>> openNOSCallback, OpenNOSCategory category)
        {
            string path = GeneratePath(OpenNOSRequestTypes.LatestAudio, category);

            var callback =
                 new RestCallback<OpenNOSResponse>((restRequest, restResponse, userState) =>
                 {
                     openNOSCallback.Invoke(restResponse.ContentEntity.LatestAudio.FirstOrDefault());
                 });

            BeginRequest<OpenNOSResponse>(callback, path);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public void GetLatestVideoAsync(OpenNOSRestCallback<IEnumerable<Video>> openNOSCallback, OpenNOSCategory category)
        {
            string path = GeneratePath(OpenNOSRequestTypes.LatestVideo, category);

            var callback =
                 new RestCallback<OpenNOSResponse>((restRequest, restResponse, userState) =>
                 {
                     openNOSCallback.Invoke(restResponse.ContentEntity.LatestVideo.FirstOrDefault());
                 });

            BeginRequest<OpenNOSResponse>(callback, path);
        }

        public void SearchContentAsync(OpenNOSRestCallback<SearchResult> openNOSCallback, string query)
        {
            string path = GenerateQueryPath(query);

            var callback =
                new RestCallback<OpenNOSResponse>((restRequest, restResponse, userState) =>
                {
                    openNOSCallback.Invoke(restResponse.ContentEntity.SearchResults.FirstOrDefault());
                });

            BeginRequest<OpenNOSResponse>(callback, path);
        }

        public void GetRadioGuideAsync(OpenNOSRestCallback<IEnumerable<GuideResult>> openNOSCallback, DateTime? startDate, DateTime? endDate, string channel)
        {
            this.GetGuideAsync(openNOSCallback, OpenNOSRequestTypes.RadioGuide, startDate, endDate, channel);
        }

        public void GetTVGuideAsync(OpenNOSRestCallback<IEnumerable<GuideResult>> openNOSCallback, DateTime? startDate, DateTime? endDate, string channel)
        {
            this.GetGuideAsync(openNOSCallback, OpenNOSRequestTypes.TVGuide, startDate, endDate, channel);
        }

        private void GetGuideAsync(OpenNOSRestCallback<IEnumerable<GuideResult>> openNOSCallback, string guide, DateTime? startDate, DateTime? endDate, string channel)
        {
            if (startDate == null && endDate != null)
            {
                throw new ArgumentException("StartDate is not filled in");
            }

            if (startDate != null && endDate == null)
            {
                throw new ArgumentException("EndDate is not filled in");
            }

            string path = GenerateGuidePath(guide, startDate, endDate, channel);

            var callback =
                new RestCallback<OpenNOSResponse>((restRequest, restResponse, userState) =>
                {
                    openNOSCallback.Invoke(restResponse.ContentEntity.GuideResults.FirstOrDefault());
                });

            BeginRequest<OpenNOSResponse>(callback, path);
        }

        private void BeginRequest<T>(RestCallback<T> callback, string path)
        {
            var request = new RestRequest
            {
                Path = path
            };

            Client.BeginRequest<T>(request, callback);
        }
    }
}
